package edu.mit.csail.relo.jdt.builder.asm;

import java.util.List;

import edu.mit.csail.relo.jdt.RJCore;
import edu.mit.csail.relo.jdt.builder.ReloRDFBuildProcessor;
import edu.mit.csail.relo.modelBridge.Artifact;
import edu.mit.csail.relo.modelBridge.DirectedRel;


//@tag design-todo: unify transformer design pattern
public class AnonymousMethodsBuildProcessor extends ReloRDFBuildProcessor {

	interface Transformer {
		void transform(Artifact codeArt);
	}

	class Joiner implements Transformer {
		public void transform(Artifact codeArt) {
	    	List<Artifact> called = codeArt.listArt(rdfRepo, DirectedRel.getFwd(RJCore.calls));
	    	List<Artifact> calling = codeArt.listArt(rdfRepo, DirectedRel.getRev(RJCore.calls));
	    	for (Artifact callingMeth : calling) {
	        	for (Artifact calledMeth : called) {
	    			rdfRepo.addStatement(callingMeth.elementRes, RJCore.calls, calledMeth.elementRes);
	    		}
			}
	    	rdfRepo.removeStatements(codeArt.elementRes, rdfRepo.rdfType, null);
		}
	}

	class Unjoiner implements Transformer {
		public void transform(Artifact codeArt) {
	    	List<Artifact> called = codeArt.listArt(rdfRepo, DirectedRel.getFwd(RJCore.calls));
	    	List<Artifact> calling = codeArt.listArt(rdfRepo, DirectedRel.getRev(RJCore.calls));
	    	for (Artifact callingMeth : calling) {
	        	for (Artifact calledMeth : called) {
	    			rdfRepo.removeStatements(callingMeth.elementRes, RJCore.calls, calledMeth.elementRes);
	    		}
			}
	    	rdfRepo.addStatement(codeArt.elementRes, rdfRepo.rdfType, RJCore.methodType);
		}
		
	}

	@Override
	public void finishProcessing() {
	    transform(projArt, new Joiner());
    }
    
	@Override
	public void cleanAnnotations() {
	    transform(projArt, new Unjoiner());
    }

    private void transform(Artifact codeArt, Transformer transformer) {
		// do a depth first traversal of the containment heirarchy while 'transforming'
		// 'transforming' = {preCondition: search for anonymous methods} do a join on method calls

    	List<Artifact> children = codeArt.getChildrenArtifacts(rdfRepo);
    	for (Artifact child : children) {
			transform(child, transformer);
		}
    	if (!rdfRepo.hasStatement(codeArt.elementRes, AsmMethodVisitor.anonymousMethodType, true)) return;
    	
    	transformer.transform(codeArt);
	}

}
